﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DoubleLinkedList
{
    public class DLL<Type> : ICollection
    {
        #region Member Variables

        private int count = 0;

        public Node<Type> First { get; set; }
        public Node<Type> Last { get; set; }
        public bool Empty { get { return First == null; } }

        #endregion

        #region Constructors

        public DLL()
        {
            First = Last = null;
        }

        #endregion

        #region Private Methods

        private Node<Type> findData(Type data)
        {
            if (First == null)   //tom lista
            {
                return null;
            }
            else
            {
                Node<Type> n = First;
                if (n.Data.Equals(data))  //datan finns i första noden
                {
                    return n;
                }
                else
                {
                    while (n.Next != null)   //leta genom listan
                    {
                        n = n.Next;
                        if (n.Data.Equals(data))
                        {
                            return n;    //datan funnen
                        }
                    }
                    return null;   //hela listan har gåtts igenom, datan ej funnen
                }
            }
        }

        #endregion

        #region Public Methods

        public void AddFirst(Type data)
        {
            if(Empty)       //listan är tom
            {
                First = new Node<Type>(data);
                Last = First;
            }
            else
            {
                Node<Type> n = new Node<Type>(data);
                n.Next = First;
                First.Prev = n;
                First = n;
            }
            count++;
        }

        public void RemoveFirst()
        {
            if (Empty)
            {
                throw new Exception("Empty list!");
            }
            else if (First == Last)
            {
                First = Last = null;
            }
            else
            {
                First = First.Next;
                First.Prev = null;
            }
        }

        public void AddLast(Type data)
        {
            if(Empty)
            {
                First = new Node<Type>(data);
                Last = First;
            }
            else
            {
                Node<Type> n = new Node<Type>(data);
                n.Prev = Last;
                Last.Next = n;
                Last = n;
            }
            count++;
        }

        public void RemoveLast()
        {
            if (Empty)
            {
                throw new Exception("Empty list!");
            }
            else if (First == Last)
            {
                First = Last = null;
            }
            else
            {
                Last = Last.Prev;
                Last.Next = null;
            }
        }

        public void Clear()
        {
            First = Last = null;
            count = 0;
        }

        public bool Contains(Type data)
        {
            Node<Type> n = findData(data);
            if (n == null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public Node<Type> Find(Type data)
        {
            Node<Type> n = findData(data);
            if (n == null)
            {
                throw new Exception("Data couldn't be found!");
            }
            else
            {
                return n;
            }            
        }

        public void Remove(Type data)
        {
            Node<Type> n = findData(data);
            if (n == null)
            {
                throw new Exception("Data couldn't be found!");
            }
            else
            {
                if (n == First)     //datan finns i första noden
                {
                    First = n.Next;
                    n.Next.Prev = null;
                }
                else if (n == Last)
                {
                    Last = n.Prev;
                    n.Prev.Next = null;
                }
                else
                {
                    n.Prev.Next = n.Next;
                    n.Next.Prev = n.Prev;
                }                
            }
        }

        #endregion

        #region ICollection
        public void CopyTo(Array array, int index)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { return count; }
        }

        public bool IsSynchronized
        {
            get { throw new NotImplementedException(); }
        }

        public object SyncRoot
        {
            get { throw new NotImplementedException(); }
        }

        public IEnumerator GetEnumerator()
        {
            Node<Type> n = First;
            while(n != Last)
            {
                yield return n;
                n = n.Next;
            }
        }

        IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }
}
